package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;

@Component("movingAvgStdPredict")
public class MovingAvgStdPredict extends PredictPlugin {

    private final int windowSize = 5;
    private final double maxDeviationAdjust = 0.2;

    @Override
    public String getName() {
        return "movingAvgStdPredict";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);

        Map<Integer, Map<Long, List<RedPacketRecord>>> grouped = new HashMap<>();
        for (RedPacketRecord r : history) {
            grouped.computeIfAbsent(r.getIndex(), k -> new HashMap<>())
                    .computeIfAbsent(r.getRoundId(), k -> new ArrayList<>())
                    .add(r);
        }

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            Map<Long, List<RedPacketRecord>> rounds = grouped.getOrDefault(idx, Collections.emptyMap());
            if (rounds.isEmpty()) {
                results.add(new PredictionResult(idx, 0, 0, 0.5, 0));
                continue;
            }

            List<Long> sortedRounds = new ArrayList<>(rounds.keySet());
            Collections.sort(sortedRounds);
            int size = sortedRounds.size();
            int start = Math.max(0, size - windowSize);
            List<Long> recentRounds = sortedRounds.subList(start, size);

            List<Double> ratios = new ArrayList<>();
            for (Long roundId : recentRounds) {
                List<RedPacketRecord> recs = rounds.get(roundId);
                int total = recs.size();
                int oddCount = (int) recs.stream().filter(r -> PredictUtils.isAmountOdd(r.getAmount())).count();
                ratios.add(oddCount / (double) total);
            }

            if (ratios.isEmpty()) {
                results.add(new PredictionResult(idx, 0, 0, 0.5, 0));
                continue;
            }

            double mean = ratios.stream().mapToDouble(Double::doubleValue).average().orElse(0);
            double variance = ratios.stream()
                    .mapToDouble(r -> (r - mean) * (r - mean))
                    .average().orElse(0);
            double stddev = Math.sqrt(variance);
            double latestRatio = ratios.get(ratios.size() - 1);
            double deviation = stddev == 0 ? 0 : (latestRatio - mean) / stddev;

            double predictedProb = latestRatio + maxDeviationAdjust * deviation;
            if (predictedProb > 0.99) {
                predictedProb = 0.99;
            }
            if (predictedProb < 0.01) {
                predictedProb = 0.01;
            }

            // 汇总统计
            int total = 0, oddCount = 0;
            for (List<RedPacketRecord> recs : rounds.values()) {
                total += recs.size();
                oddCount += recs.stream().filter(r -> PredictUtils.isAmountOdd(r.getAmount())).count();
            }
            double avgOpenTime = rounds.values().stream()
                    .flatMap(Collection::stream)
                    .mapToInt(RedPacketRecord::getOpenTime)
                    .average()
                    .orElse(0);

            results.add(new PredictionResult(idx, total, oddCount, predictedProb, Double.valueOf(avgOpenTime+"").intValue()));
        }
        return results;
    }
}
